﻿using System.Windows;
using Microsoft.Phone.Controls;

namespace MemoryTest_Communications
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Reactive.Linq;
    using Microsoft.Phone.Info;
    using Model;
    using PropertySearch;
    using Serialization;
    using WP7Contrib.Caching;
    using WP7Contrib.Collections;
    using WP7Contrib.Common;
    using WP7Contrib.Communications;
    using WP7Contrib.Logging;

    public partial class MainPage : PhoneApplicationPage
    {
        private const string PageInfo = "Page index {0}, page size {1}";
        private const string PropertyCount = "Foo count {0} of {1}";
        private const string SerializedListSize = "Serialized Foo list size = {0:N0} bytes";
        private const string AverageSize = "Average serialized Foo size = {0:N0} bytes";

        private const string StartMemoryUsage   = "Start Memory Usage = {0:N0} bytes";
        private const string CurrentMemoryUsage = "Current Memory Usage = {0:N0} bytes";
        private const string DeltaMemoryUsage   = "Delta = {0:N0} bytes";

        private readonly ObservableCollection<Property> properties = new ObservableCollection<Property>();

        private readonly ISearchForProperties propertySearch;

        private const int PageSize = 42;
        private int pageIndex = 1;
        private readonly ILog log;

        private int propertiesAvailable = 0;

        private readonly int emptyListSize = 0;

        private int startMemoryValue = 0;
        private int currentMemoryValue = 0;

        // Constructor
        public MainPage()
        {
            InitializeComponent();

            log = new LoggingService("MemoryTest_Communications");

            SilverlightSerializer.RegisterSerializationAssembly(typeof(BaseModel).GetType().Assembly);
            SilverlightSerializer.RegisterSerializationAssembly(typeof(NullLoggingService).GetType().Assembly);
            SilverlightSerializer.RegisterSerializationAssembly(this.GetType().Assembly);

            emptyListSize = SilverlightSerializer.Serialize(new List<Property>()).Length;

            propertySearch = new PropertySearchService(new ResourceClient(log),
                                                       new OneSecondThrottler(),
                                                       new UrlEncoder(),
                                                       new NullCacheProvider(),
                                                       log);

            Reset();
            Update();
        }

        private void nextPage_Click(object sender, RoutedEventArgs e)
        {
            DoSearch();
        }

        private void search_Click(object sender, RoutedEventArgs e)
        {
            Reset();
            DoSearch();
        }

        private void Update()
        {
            pageInfo.Text = string.Format(PageInfo, pageIndex, PageSize);
            propertyCount.Text = string.Format(PropertyCount, properties.Count, propertiesAvailable);

            var propertyList = properties.ToList();
            var data = SilverlightSerializer.Serialize(propertyList);

            serializedCollectionSize.Text = string.Format(SerializedListSize, data.Length);

            var average = properties.Count != 0 ? (data.Length - emptyListSize) / properties.Count : 0 ;
            averageSerializedSize.Text = string.Format(AverageSize, average);

            currentMemoryValue = Convert.ToInt32(GetDeviceExtendedProperties("ApplicationCurrentMemoryUsage"));

            startMemory.Text = string.Format(StartMemoryUsage, startMemoryValue);
            currentMemory.Text = string.Format(CurrentMemoryUsage, currentMemoryValue);
            deltaMemory.Text = string.Format(DeltaMemoryUsage, currentMemoryValue - startMemoryValue);
        }

        private void Reset()
        {
            startMemoryValue = Convert.ToInt32(GetDeviceExtendedProperties("ApplicationCurrentMemoryUsage"));

            pageIndex = 1;
            properties.Clear();

            GC.Collect();
        }

        private void DoSearch()
        {
            propertySearch.Search(pageIndex, PageSize, new PropertyCriteria { PlaceName = this.searcchAddress.Text })
               .ObserveOnDispatcher()
               .Subscribe(result =>
               {
                   log.Write("Processing results");
                   foreach (var property in result.Properties)
                   {
                       if (!properties.Contains(property))
                           properties.Add(property);
                   }

                   propertiesAvailable = result.Properties.Total;

                   GC.Collect();
                   this.Update();
                   pageIndex++;
               },
               exn => log.Write("FAILED SEARCH", exn));
        }

        private static object GetDeviceExtendedProperties(string propertyName)
        {
            try
            {
                object value;
                if (DeviceExtendedProperties.TryGetValue(propertyName, out value))
                {
                    return value.GetType() == typeof(byte[]) ? ConvertByteArrayToString((byte[])value) : value;
                }

                return string.Empty;
            }
            catch (Exception)
            {
                return string.Empty;
            }
        }

        private static string ConvertByteArrayToString(IEnumerable<byte> value)
        {
            var stringValue = string.Empty;
            value.ToList().ForEach(b => stringValue += b);

            return stringValue;
        }
    }
}